package com.atguigu.gmall.item.service.impl;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.item.service.ItemService;
import com.atguigu.gmall.list.client.ListFeignClient;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.product.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author: atguigu
 * @create: 2023-09-02 16:15
 */
@Slf4j
@Service
public class ItemServiceImpl implements ItemService {

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private ListFeignClient listFeignClient;


    /**
     * 汇总渲染商品详情页面所需要数据模型
     * 远程调用商品服务获取七项商品相关信息
     * ${categoryView}-三级分类
     * ${skuInfo}-商品sku信息
     * ${price}-商品价格
     * ${spuPosterList} 海报图片
     * ${skuAttrList} sku平台属性信息
     * ${spuSaleAttrList} 销售属性列表
     * ${valuesSkuJson} 切换商品SKU
     *
     * @param skuId
     * @return
     */
    @Override
    public Map<String, Object> getSkuInfo(Long skuId) {

        //0.查询布隆过滤器中是否包含查询商品skuId
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConst.SKU_BLOOM_FILTER);
        boolean exists = bloomFilter.contains(skuId);
        if (!exists) {
            log.error("[详情服务]访问商品不存在：{}", skuId);
            throw new RuntimeException("访问商品不存在:" + skuId);
        }

        //Map<String, Object> mapResult = new HashMap<>();  //多线程并发写hashMap导致key被覆盖
        ConcurrentHashMap<String, Object> mapResult = new ConcurrentHashMap<>();
        //1.根据商品SkuId查询商品信息 skuinfo信息异步任务需要返回结果，提供给其他异步任务使用
        CompletableFuture<SkuInfo> skuInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            if (skuInfo == null) {
                throw new RuntimeException("远程调用商品不存在！");
            }
            mapResult.put("skuInfo", skuInfo);
            return skuInfo;
        }, threadPoolExecutor);


        //2.根据商品分类ID查询分类信息 获取商品信息异步任务结果，当前任务不需要返回结果
        CompletableFuture<Void> categoryViewCOmCompletableFuture = skuInfoCompletableFuture.thenAcceptAsync(skuInfo -> {
            BaseCategoryView categoryView = productFeignClient.getCategoryView(skuInfo.getCategory3Id());
            if (categoryView != null) {
                mapResult.put("categoryView", categoryView);
            }
        }, threadPoolExecutor);

        //3.根据商品SkuId查询商品价格
        CompletableFuture<Void> priceCompletableFuture = CompletableFuture.runAsync(() -> {
            BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
            if (skuPrice != null) {
                mapResult.put("price", skuPrice);
            }
        }, threadPoolExecutor);

        //4.根据商品SpuId查询海报图片列表
        CompletableFuture<Void> spuPosterListCOmCompletableFuture = skuInfoCompletableFuture.thenAcceptAsync(skuInfo -> {
            List<SpuPoster> spuPosterList = productFeignClient.getSpuPosterBySpuId(skuInfo.getSpuId());
            if (!CollectionUtils.isEmpty(spuPosterList)) {
                mapResult.put("spuPosterList", spuPosterList);
            }
        }, threadPoolExecutor);

        //5.根据skuId查询商品平台属性列表
        CompletableFuture<Void> skuAttrListCompletableFuture = CompletableFuture.runAsync(() -> {
            List<BaseAttrInfo> baseAttrInfoList = productFeignClient.getAttrListBySkuId(skuId);
            if (!CollectionUtils.isEmpty(baseAttrInfoList)) {
                mapResult.put("skuAttrList", baseAttrInfoList);

            }
        }, threadPoolExecutor);

        //6.根据skuId,spuId获取所有销售属性，带选中当前sku销售属性值
        CompletableFuture<Void> spuSaleAttrListCompletableFuture = skuInfoCompletableFuture.thenAcceptAsync(skuInfo -> {
            List<SpuSaleAttr> spuSaleAttrListCheckBySku = productFeignClient.getSpuSaleAttrListCheckBySku(skuId, skuInfo.getSpuId());
            if (!CollectionUtils.isEmpty(spuSaleAttrListCheckBySku)) {
                mapResult.put("spuSaleAttrList", spuSaleAttrListCheckBySku);
            }
        }, threadPoolExecutor);

        //7.切换商品SKU字符串
        CompletableFuture<Void> valuesSkuJsonCompletableFuture = skuInfoCompletableFuture.thenAcceptAsync(skuInfo -> {
            String changeSkuValueIdsString = productFeignClient.getChangeSkuValueIdsMap(skuInfo.getSpuId());
            if (StringUtils.isNotBlank(changeSkuValueIdsString)) {
                mapResult.put("valuesSkuJson", changeSkuValueIdsString);
            }
        }, threadPoolExecutor);

        //8.远程调用搜索服务对商品分值进行修改
        CompletableFuture<Void> hotScoreCompletableFuture = CompletableFuture.runAsync(() -> {
            listFeignClient.incrHotScore(skuId.toString(), 1);
        }, threadPoolExecutor);


        //x.组合以上七个异步任务
        CompletableFuture.allOf(
                skuInfoCompletableFuture,
                categoryViewCOmCompletableFuture,
                spuPosterListCOmCompletableFuture,
                spuSaleAttrListCompletableFuture,
                valuesSkuJsonCompletableFuture,
                priceCompletableFuture,
                skuAttrListCompletableFuture,
                hotScoreCompletableFuture
        ).join();
        return mapResult;
    }


    public static void main(String[] args) throws InterruptedException {
        Map<String, String> map = new HashMap<>();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                String s = UUID.randomUUID().toString();
                map.put(s, "a");
                countDownLatch.countDown();
            }).start();
        }

        countDownLatch.await();
        System.out.println(map.size());
    }
}
